
#ifndef RTUDPENDPOINTMGR_H
#define RTUDPENDPOINTMGR_H

#include "RtUtilTemplates.h"
#include "RtHashMapT.h"
#include "RtPairInetAddr.h"
#include "RtPairIpPort.h"
#include "RtReactorInterface.h"
#include "RtSocket.h"
#include "RtAcceptorUdp.h"

class CRtUdpEndpoint;
class CRtTransportUdp;

typedef CRtPairIpPort CRtUdpEndpointKey;
typedef CRtHashMapT<CRtUdpEndpointKey, CRtAutoPtr<CRtUdpEndpoint> > UdpEndpointsType;
typedef CRtHashMapT<CRtPairInetAddr, CRtAutoPtr<CRtTransportUdp> > UdpTransportsType;

class CRtUdpEndpointManager
{
public:
	static CRtUdpEndpointManager* Instance()
	{
		return CRtSingletonT<CRtUdpEndpointManager>::Instance();
	}

	RtResult StartListen(
		IRtAcceptor* aAcceptor, 
		IRtAcceptorConnectorSink *aSink, 
		const CRtInetAddr &aAddrListen,
		BOOL aListenForRudp);
	RtResult StopListen(const CRtInetAddr &aAddrListen);
	RtResult Connect(
		const CRtInetAddr& aPeerAddr, 
		const CRtInetAddr* aLocalAddr,
		CRtTransportUdp*& aTrpt);

	void RemoveEndpoint(CRtUdpEndpoint* pEndpoint);

protected:
	friend class CRtSingletonT<CRtUdpEndpointManager>;
	CRtUdpEndpointManager();
	virtual ~CRtUdpEndpointManager();

private:
	UdpEndpointsType m_endpoints;
};

class CRtUdpEndpoint
: public IRtEventHandler 
, public CRtReferenceControlSingleThreadTimerDelete
{
public:
	CRtUdpEndpoint(CRtUdpEndpointManager* pManager);
	virtual ~CRtUdpEndpoint();

	/// from IRtEventHandler
	virtual RT_HANDLE GetHandle() const { return m_socket.GetHandle(); }
	virtual int OnInput(RT_HANDLE aFd = RT_INVALID_HANDLE);
	virtual int OnClose(RT_HANDLE aFd, MASK aMask);

	RtResult StartListen(
		IRtAcceptor* aAcceptor, 
		IRtAcceptorConnectorSink *aSink, 
		const CRtInetAddr &aAddrListen,
		BOOL aListenForRudp);
	RtResult StopListen();
	RtResult Connect(
		const CRtInetAddr& aPeerAddr, 
		const CRtInetAddr* aLocalAddr,
		CRtTransportUdp*& aTrpt);

	const CRtInetAddr& GetLocalAddr() const { return m_localAddr; }
	CRtSocketDgram& GetSocket() { return m_socket; }
	void RemoveTransport(const CRtInetAddr &aPeerAddr);

private:
	RtResult Open(const CRtInetAddr& aLocalAddr, const CRtInetAddr* aRemoteAddr=NULL);
	void Close();

private:
	CRtUdpEndpointManager* m_pManager;
	IRtReactor* m_pReactor;
	IRtAcceptor* m_pAcceptor;
	IRtAcceptorConnectorSink* m_pAcceptorSink;
	BOOL m_listenForRudp;
	CRtSocketDgram m_socket;
	CRtInetAddr m_localAddr;
	UdpTransportsType m_transports;
};


inline void CRtUdpEndpointManager::RemoveEndpoint(CRtUdpEndpoint* pEndpoint)
{
	CRtUdpEndpointKey key(pEndpoint->GetLocalAddr());
	int n = m_endpoints.erase(key);
	RT_ASSERTE(n==1);
}

#endif // !RTUDPENDPOINTMGR_H
